package com.lwj.utils.excel;

import com.alibaba.excel.EasyExcelFactory;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.metadata.Head;
import com.alibaba.excel.write.builder.ExcelWriterBuilder;
import com.alibaba.excel.write.handler.WriteHandler;
import com.alibaba.excel.write.metadata.WriteSheet;
import com.alibaba.excel.write.metadata.style.WriteCellStyle;
import com.alibaba.excel.write.metadata.style.WriteFont;
import com.alibaba.excel.write.style.HorizontalCellStyleStrategy;
import com.alibaba.excel.write.style.column.AbstractHeadColumnWidthStyleStrategy;
import com.lwj.exception.BusinessException;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.ss.util.CellRangeAddress;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.servlet.DispatcherServlet;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.OutputStream;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class EasyExcelUtils {
    protected final Logger logger = LoggerFactory.getLogger(getClass());
    private String headFont = "黑体";
    private String contentFont = "宋体";
    private Integer headSize = 10;
    private Integer contentSize = 11;
    private Short headHigh = 2;
    private Boolean wrapped=true;
    private List<WriteHandler> writeHandlers=new ArrayList<>();



    public EasyExcelUtils() {
    }
    public EasyExcelUtils(String waterStr) {
        this.writeHandlers.add(new WaterMarkStrategy(waterStr));
        this.writeHandlers.add(defaultStyleStrategy());
    }



    public Boolean getWrapped() {
        return wrapped;
    }

    public void setWrapped(Boolean wrapped) {
        this.wrapped = wrapped;
    }

    public String getHeadFont() {
        return headFont;
    }

    public void setHeadFont(String headFont) {
        this.headFont = headFont;
    }

    public String getContentFont() {
        return contentFont;
    }

    public void setContentFont(String contentFont) {
        this.contentFont = contentFont;
    }

    public Integer getHeadSize() {
        return headSize;
    }

    public void setHeadSize(Integer headSize) {
        this.headSize = headSize;
    }

    public Integer getContentSize() {
        return contentSize;
    }

    public void setContentSize(Integer contentSize) {
        this.contentSize = contentSize;
    }
    public void addWriteHandlers(WriteHandler writeHandler){
        this.writeHandlers.add(writeHandler);
    }

    public WriteHandler defaultStyleStrategy() {
        WriteCellStyle headWriteCellStyle = createCellStyle(headFont, headSize, wrapped, HorizontalAlignment.CENTER);
        WriteCellStyle contentWriteCellStyle = createCellStyle(contentFont, contentSize, wrapped, HorizontalAlignment.CENTER);
        return new HorizontalCellStyleStrategy(headWriteCellStyle, contentWriteCellStyle);
    }

    public OutputStream getOutputStream(HttpServletResponse response, String fileName) throws IOException {
        response.setContentType("application/force-download");
        fileName= replaceSheetName(fileName);
        fileName = URLEncoder.encode(fileName + ".xlsx", StandardCharsets.UTF_8.toString());
        fileName = fileName.replaceAll("\\+", "%20");
        response.setHeader("Content-Disposition", "attachment;filename=" + fileName.replaceAll("%2B", "+"));//bug15615
        return response.getOutputStream();
    }
    public    String replaceSheetName(String sheetName) {
        if (org.apache.commons.lang3.StringUtils.isBlank(sheetName)) {
            return "";
        }
        String regex = "[/:*\"?\\\\<>|]";
        return sheetName.replaceAll(regex, "-");
    }

    public static WriteCellStyle createCellStyle(String fontName, int size, Boolean wrapped, HorizontalAlignment alignment) {
        WriteCellStyle cellStyle = new WriteCellStyle();
        cellStyle.setWrapped(wrapped);
        cellStyle.setHorizontalAlignment(alignment);
        WriteFont headWriteFont = new WriteFont();
        headWriteFont.setFontName(fontName);
        headWriteFont.setFontHeightInPoints((short) size);
        cellStyle.setWriteFont(headWriteFont);
        return cellStyle;
    }



    public void exportSheets(HttpServletResponse response, String fileName, Class templateClass,Map<String,List> map) {
        try {
            OutputStream responseOut = getOutputStream(response, fileName);
            ExcelWriter writer = initBuilder(responseOut).head(templateClass).build();
            for (Map.Entry<String, List> m : map.entrySet()) {
                WriteSheet writeSheet = new WriteSheet();
                writeSheet.setSheetName(replaceSheetName(m.getKey()));
                // 写数据
                writer.write(m.getValue(), writeSheet);
            }
            writer.finish();
            responseOut.flush();
        } catch (Exception e) {
            logger.error("导出报错", e);
            throw new BusinessException("导出报错");
        }
    }
    public ExcelWriterBuilder initBuilder( OutputStream responseOut){
        ExcelWriterBuilder excelWriterBuilder = EasyExcelFactory.write(responseOut).inMemory(true);
        for (int i = 0; i < writeHandlers.size(); i++) {
            excelWriterBuilder.registerWriteHandler(writeHandlers.get(i));
        }
        return excelWriterBuilder;
    }
    public void exportByTemplate(HttpServletResponse response, String fileName, String sheetName, List list, Class templateClass) {
        sheetName=replaceSheetName(sheetName);
        try {
            OutputStream responseOut = getOutputStream(response, fileName);
            ExcelWriter writer = initBuilder(responseOut).head(templateClass).build();
            WriteSheet writeSheet = new WriteSheet();
            writeSheet.setSheetName(sheetName);
            writer.write(list, writeSheet);
            writer.finish();
            responseOut.flush();
        } catch (Exception e) {
            logger.error("导出报错", e);
            throw new BusinessException("导出报错");
        }
    }
    public AbstractHeadColumnWidthStyleStrategy columnWidthStyleStrategy(Map<Integer, Integer> columnWidthMap){
        return new AbstractHeadColumnWidthStyleStrategy() {
            @Override
            protected Integer columnWidth(Head head, Integer integer) {
                return columnWidthMap.get(integer);
            }
        };
    }
    public void exportByCustomize(HttpServletResponse response, String fileName, String sheetName, List list, List<List<String>> headList, Map<Integer, Integer> columnWidthMap ) {
        try {
            OutputStream responseOut = getOutputStream(response, fileName);
            ExcelWriter writer = initBuilder(responseOut).head(headList).registerWriteHandler(columnWidthStyleStrategy(columnWidthMap)).build();
            WriteSheet writeSheet = new WriteSheet();
            writeSheet.setSheetName(sheetName);

            // 写数据
            writer.write(list, writeSheet);
            writer.finish();
            responseOut.flush();
        } catch (Exception e) {
            logger.error("导出报错", e);
            throw new BusinessException("导出报错");
        }
    }

    public static CellStyle createStyle(Workbook workbook) {
        CellStyle cellStyle = workbook.createCellStyle();
        // 下边框
        cellStyle.setBorderBottom(BorderStyle.THIN);
        // 左边框
        cellStyle.setBorderLeft(BorderStyle.THIN);
        // 上边框
        cellStyle.setBorderTop(BorderStyle.THIN);
        // 右边框
        cellStyle.setBorderRight(BorderStyle.THIN);
        // 水平对齐方式
        cellStyle.setAlignment(HorizontalAlignment.CENTER);
        // 垂直对齐方式
        cellStyle.setVerticalAlignment(VerticalAlignment.CENTER);
        return cellStyle;
    }

    public static void rangeCell(Sheet sheet, int startRow, int endRow, int startColumn, int endColumn) {
        CellRangeAddress cellAddresses = new CellRangeAddress(startRow, endRow, startColumn, endColumn);
        sheet.addMergedRegion(cellAddresses);
    }

    public static void initCellStyle(Cell cell, int size, String fontName, HorizontalAlignment alignment, Boolean wrapText) {
        CellStyle cellStyle = makeCellStyle(cell, size, fontName, alignment, wrapText);
        cell.setCellStyle(cellStyle);
    }

    public static CellStyle makeCellStyle(Cell cell, int size, String fontName, HorizontalAlignment alignment, Boolean wrapText) {
        Workbook workbook = cell.getSheet().getWorkbook();
        CellStyle cellStyle = workbook.createCellStyle();
        cellStyle.setWrapText(wrapText);//换行符是否生效
        cellStyle.setAlignment(alignment); // 居中:HorizontalAlignment.CENTER
        Font font = workbook.createFont();
        font.setFontName(fontName);//字体
//        font.setColor((short)10);//字体颜色为红色
//        font.setBold(true);//设置为粗体
        font.setFontHeightInPoints(((short) size));//设置字体大小
        cellStyle.setFont(font);
        return cellStyle;
    }

    public static void hiddenBorder(CellStyle style, Boolean top, Boolean bottom, Boolean right, Boolean left) {
        if (top) {
            style.setTopBorderColor(IndexedColors.WHITE.getIndex());
            style.setBorderTop(BorderStyle.THIN);
        }
        if (bottom) {
            style.setBottomBorderColor(IndexedColors.WHITE.getIndex());
            style.setBorderBottom(BorderStyle.THIN);
        }
        if (right) {
            style.setRightBorderColor(IndexedColors.WHITE.getIndex());
            style.setBorderRight(BorderStyle.THIN);
        }
        if (left) {
            style.setLeftBorderColor(IndexedColors.WHITE.getIndex());
            style.setBorderLeft(BorderStyle.THIN);
        }
    }
}
